
#include "stm32f10x.h"
#include "sysconfig.h"
#include "rtthread.h"
#include "rthw.h"

#define FLASH_PAGESIZE  2048

typedef struct {
    syscfg_t config;
    uint8_t reserved[FLASH_PAGESIZE - sizeof(syscfg_t)];
} syscfg_area_t;

static const syscfg_area_t syscfg_area __attribute__((aligned(FLASH_PAGESIZE))) = {
    .config = {
        .crc32 = {0, 0},
        .enc_key = 0,
        .firm_info = {
            .version = {1, 0, 0, 0}, /* V1.0.0.0 */
            .date = { __DATE__ },
            .time = { __TIME__ }
        },
        .board_info = {
            .id = (uint32_t)-1,
            .serial_no = { "a732_b7fA_3xM8" },
        },
        .key_enable = 1,
    },
    .reserved = {0xff}
};

int load_syscfg(syscfg_t* cfg)
{
    if (cfg)
    {
        rt_memcpy(cfg, &syscfg_area.config, sizeof(syscfg_t));
    }
    return 0;
}

const syscfg_t *get_syscfg(void)
{
    return &syscfg_area.config;
}

int save_syscfg(const syscfg_t *cfg)
{
    if (!cfg)
    {
        return -1;
    }

    rt_base_t level = rt_hw_interrupt_disable();

    uint32_t *from = (uint32_t *)cfg;
    uint32_t *to = (uint32_t *)&syscfg_area;
    FLASH_Unlock();
    FLASH_ClearFlag(FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);
    FLASH_ErasePage((uint32_t)to);
    for(int i = 0; i < FLASH_PAGESIZE / 4; i ++)
    {
        FLASH_ProgramWord((uint32_t)&to[i], from[i]);
    }
    FLASH_Lock();

    rt_hw_interrupt_enable(level);
    return 0;
}


#if defined RT_USING_FINSH && defined RT_USING_CONSOLE
#include "finsh.h"
#include "led_key.h"

static int key_en(int argc, char *argv[])
{
    if (argc != 2)
    {
        return 0;
    }

    uint8_t en;
    if (argv[1][0] == '1')
    {
        en = 1;
        rt_key_enable();
    }
    else if (argv[1][0] == '0')
    {
        rt_key_disable();
        en = 0;
    }
    else
    {
        rt_kprintf("key_en para err!\n");
        return 0;
    }

    if (en == get_syscfg()->key_enable)
    {
        rt_kprintf("key_en is already %d!\n", en);
        return 0;
    }

    syscfg_t *buf = rt_malloc_align(sizeof(syscfg_t), 16);
    if (!buf)
    {
        rt_kprintf("key_en malloc err!\n");
        return 0;
    }

    load_syscfg(buf);
    buf->key_enable = en;
    save_syscfg(buf);
    rt_kprintf("key_en ok!\n");

    return 0;
}
MSH_CMD_EXPORT(key_en, enable or disable key);
#endif
